<script>
  import $ from '../dfish.js'
  import {
    h, ref
  } from 'vue'
  import FormBase from './FormBase.vue'
  import Horizontal from './Horizontal.vue'

  export default {
    name: 'w-checkbox',
    pubParentName: 'w-checkboxgroup',
    mixins: [FormBase],
    props: ['text', 'checked', 'partialSubmit', 'minSize', 'maxSize'],
    inject: ['providePubParent', 'provideBoxParent'],
    emits: ['change', 'update:checked', 'click'],
    data() {
      return {
        isPlural: true,
        indeterminate: false,
        modifiedChecked: false,
        defaultChecked: false,
      }
    },
    created() {
      if (this.provideBoxParent) {
        this.provideBoxParent.boxProxy = this
      }
      if (this.pubParent) {
        if (this.$slots.default)
          this.pubParent.isGrid = true
      }
      this.defaultChecked = this.isChecked
      this.modifiedChecked = this.isChecked
    },
    methods: {
      val(a) {
        if (arguments.length == 0) {
          return this.getVal()
        }
        this.setVal(a, {
          type: 'change',
          target: this.$refs.v
        })
      },
      getVal() {
        return this.isChecked ? this.value : ''
      },
      setVal(checked, event) {
        let p = this.pubParent
        let v = this.$refs.v.value
        let rdo = this.input_type === 'radio'
        if (rdo && checked) {
          $.lodash.each(this.siblings(), f => {
            if(f != this && f.x.checked) {
              f.check(false)
              return false
            }
          })
        }
        if (typeof this.x.checked === 'boolean') {
          this.check(checked)
        }
        if (p) {
          let mv = p.x.modelValue || ''
          if (rdo) {
            mv = checked ? v : ''
          } else {
            mv = checked ? $.idsAdd(mv, v) : $.idsRemove(mv, v)
          }
          p.x.modelValue = mv
          p.trigger('update:modelValue', mv)
          p.trigger(event, mv)
        } else {
          this.trigger(event, checked ? v : '')
        }
      },
      formVal() {
        return !this.isDisabled && this.isChecked ? this.x.value : ''
      },
      groupFormVal(a) {
        if (a == null) {
          let r = []
          $.lodash.each(this.siblings(null, true), f => {
            let g = f.formVal()
            if (g != null && g != '') r.push(g)
          })
          return r.join(',')
        }
        $.lodash.each(this.siblings(), f => f.check($.idsAny(a, f.formVal())))
      },
      
      // @a -> T/F 是否只获取所有选中项, b -> 是否只选择可用的
      siblings(a, b) {
        return $.lodash.map($.q(':input[name="' + this.input_name + '"]' + (b ? ':not(:disabled)' : '') +
          (a === true ? ':checked' : a === false ? ':not(:checked)' : (a || '')), this.ownerView.el()), e => $(e))
      },
      check(a) {
        this.x.checked = a
      },
      relate() {
        // implement
      },
      // @empty -> 是否强制清空
      reset(empty) {
        if (this.pubParent) {
          this.pubParent.reset(empty)
        } else {
          this.val(empty || !this.defaultChecked ? false : true)
        }
      },
      onclick(e) {
        //implement
        e.stopPropagation()
      },
      onchange(e) {
        if (this.warnClass && this.x.name) {
          this.ownerView.fAll(this.x.name).forEach(v => v.warn && v.warn(false))
        }
        this.setVal(e.target.checked, e)
        this.trigger('click', e)
      },
      isModified(original) {
        if (this.pubParent) {
          return this.pubParent.isModified(original)
        } else {
          let c = original ? this.defaultChecked : this.modifiedChecked
          return c == this.isChecked
        }
      },
      saveModified(original) {
        if (this.pubParent) {
          this.pubParent.saveModified(original)
        } else {
          this.modifiedChecked = this.isChecked
          if (original) {
            this.defaultChecked = this.modifiedChecked
          }
        }
      },
      snapElem() {
        return this.el()
      },
      html_input() {
        return [h(this.input_tag, {
            ref: 'v',
            class: 'w-input-value',
            type: this.input_type,
            name: this.input_name,
            value: this.input_value,
            checked: this.isChecked,
            disabled: this.isDisabled,
            onclick: e => {
              if (this.isNormal) {
                if (!this.pubParent) {
                  this.x.checked = e.target.checked
                }
                this.indeterminate = false
              } else e.preventDefault()
            },
            onchange: this.onchange,
            ...this.input_prop,
          }), h('em', {
            class: this.$options.name + '-appear'
          }, h('i', {
            class: this.input_icon
          })),
          this.x.text ?
          h('span', {
            class: this.$options.name + '-text'
          }, this.x.text) : null
        ]
      },
      html_main() {
        return h('label', {
          class: 'w-input',
          onclick: this.onclick,
        }, this.html_input())
      },
      html_target() {
        return h(Horizontal, {
          class: this.$options.name + '-target',
          ref: 'target'
        }, this.$slots)
      },
      html() {
        return this.pubParent && this.pubParent.isGrid ? [this.html_self(true), this.html_target()] : this.html_self()
      }
    },
    computed: {
      validHooks() {
        return {
          ...this.pubValidHooks,
          minSize: (v, r, q) => {
            if (v && r != null && r !== '' && r > 0 && v.split(',').length < $.number(r))
              return this.formErr(q, [r])
          },
          maxSize: (v, r, q) => {
            if (v && r != null && r !== '' && r > 0 && v.split(',').length > $.number(r))
              return this.formErr(q, [r])
          },
        }
      },
      rules() {
        return {
          required: this.x.required != null ? this.x.required : (this.pubParent && this.pubParent.x.required),
          minSize: this.x.minSize != null ? this.x.minSize : (this.pubParent && this.pubParent.x.minSize),
          maxSize: this.x.maxSize != null ? this.x.maxSize : (this.pubParent && this.pubParent.x.maxSize),
        }
      },
      input_type() {
        return 'checkbox'
      },
      input_name() {
        return this.x.name || (this.pubParent && this.pubParent.x.name)
      },
      input_value() {
        // 如果没有定义value，必须返回空字符串。因为当<input type="checkbox">没有value属性时，它的表单值会变成"on"
        return this.x.value == null ? '' : this.x.value
      },
      input_prop() {
        return {
          indeterminate: this.indeterminate,
          'w-partialsubmit': this.x.partialSubmit ? 1 : null,
        }
      },
      input_icon() {
        return 'f-i f-i-check'
      },
      isChecked() {
        return typeof this.x.checked === 'boolean' ? this.x.checked : (this.pubParent && $.idsAny(this.pubParent.x.modelValue, this.x.value))
      },
      isDisabled() {
        return this.x.disabled != null ? this.x.disabled : (this.pubParent && this.pubParent.disabled)
      },
      isReadonly() {
        return this.x.readonly != null ? this.x.readonly : (this.pubParent && this.pubParent.readonly)
      },
      html_class() {
        return {
          'z-half': this.indeterminate
        }
      }
    },
    mounted() {
      let t = this.$refs.target
      if (t) {
        this.$nextTick(() => {
          this.$watch(() => this.isChecked && !this.isDisabled, (v) => {
            this.ownerView && t.$el && this.ownerView.fAll(null, t.$el).forEach(n => n.x.disabled = !v)
          }, {
            immediate: true
          })
        })
      }
    },
  }
</script>
